package com.rlyy.grpc.server;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.PropertyNamingStrategy;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.rlyy.common.enums.CommonEnum;
import com.rlyy.common.param.Request;
import com.rlyy.basic.process.AbstractProcessorDispatcher;
import com.rlyy.basic.resolver.exception.MyExceptionHandlerExceptionResolver;
import com.rlyy.common.response.Result;
import com.rlyy.common.response.ResultUtil;
import com.rlyy.basic.trace.ITraceProcess;
import com.rlyy.common.param.LinkTrace;
import com.rlyy.basic.trace.TraceCombination;
import com.rlyy.grpc.lib.GrpcInterfaceGrpc;
import com.rlyy.grpc.lib.RequestMessage;
import com.rlyy.grpc.lib.ResponseMessage;
import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.server.service.GrpcService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.reflect.InvocationTargetException;
import java.util.Optional;


/**
 * @author yuanqinglong
 * @since 2020/11/26 14:31
 */
@GrpcService
public class GrpcRequestHandler extends GrpcInterfaceGrpc.GrpcInterfaceImplBase {

    static final Logger logger = LoggerFactory.getLogger(GrpcRequestHandler.class);

    static final SerializeConfig SERIALIZE_CONFIG = new SerializeConfig();

    static {
        SERIALIZE_CONFIG.propertyNamingStrategy = PropertyNamingStrategy.SnakeCase;
    }

    @Autowired
    private AbstractProcessorDispatcher defaultProcessorDispatcher;

    @Autowired
    private MyExceptionHandlerExceptionResolver exceptionResolver;

    @Autowired
    private ITraceProcess iTraceProcess;

    @Override
    public void handler(RequestMessage request, StreamObserver<ResponseMessage> responseObserver) {
        String requestData = request.getData();
        Result result = null;
        long startTime = System.currentTimeMillis();
        Request grpcRequest;
        try {
            grpcRequest = JSONObject.parseObject(requestData, Request.class);
        } catch (Exception e) {
            logger.error("参数解析异常:{}, 参数:{}", e, requestData);
            response(responseObserver, ResultUtil.error(CommonEnum.PARAMETER_PARSING_ERROR));
            return;
        }
        LinkTrace tracking = iTraceProcess.tracking(new TraceCombination(grpcRequest));
        try {
            result = defaultProcessorDispatcher.process(grpcRequest);
            tracking.setDuration((System.currentTimeMillis() - startTime));
        } catch (Exception e) {
            // 调用invoke执行目标方法 统一处理目标方法抛出的异常和记录日志
            tracking.setResult("FAILURE");
            Throwable throwable = e instanceof InvocationTargetException ? ((InvocationTargetException) e).getTargetException() : e;
            result = exceptionResolver.invokeExceptionMethod(throwable);
        } finally {
            iTraceProcess.syncPrintTracking(tracking);
            response(responseObserver, result);
        }
    }





    /**
     * 返回信息
     *
     * @param responseObserver response
     * @param result           返回信息提示
     */
    public static void response(StreamObserver<ResponseMessage> responseObserver, Object result) {
        responseObserver.onNext(ResponseMessage.newBuilder().setData(JSONObject.toJSONString(result, SERIALIZE_CONFIG, SerializerFeature.WriteMapNullValue)).build());
        responseObserver.onCompleted();
    }

    /**
     * 返回处理结果
     *
     * @param formatFullRequest 请求信息
     * @param result            返回结果
     * @param responseObserver  .
     */
    public static void returnResult(Request formatFullRequest, Result result, StreamObserver<ResponseMessage> responseObserver) {
        if (formatFullRequest == null) {
            returnResult(result, responseObserver);
            return;
        }
        result = Optional.ofNullable(result).orElseGet(() -> ResultUtil.error(CommonEnum.SERVER_IS_BUSY));
        //result.setTid(formatFullRequest.getTid());
        //返回结果
        GrpcRequestHandler.response(responseObserver, result);
    }


    /**
     * 返回处理结果
     *
     * @param result           返回结果
     * @param responseObserver .
     */
    public static void returnResult(Result result, StreamObserver<ResponseMessage> responseObserver) {
        result = Optional.ofNullable(result).orElseGet(() -> ResultUtil.error(CommonEnum.PARAMS_NOT_ENOUGH));
        //返回结果
        GrpcRequestHandler.response(responseObserver, result);
    }

}
